#!/usr/bin/env python3
"""
日志分析工具图形界面
"""

import tkinter as tk
from tkinter import ttk, filedialog, messagebox, simpledialog
import os
import threading
from pathlib import Path
from log_analyzer import LogAnalyzer


class SettingsWindow:
    """设置窗口"""
    def __init__(self, parent, pattern_var, output_dir_var):
        self.parent = parent
        self.pattern_var = pattern_var
        self.output_dir_var = output_dir_var
        
        self.window = tk.Toplevel(parent)
        self.window.title("设置")
        self.window.geometry("400x200")
        self.window.transient(parent)
        self.window.grab_set()
        
        self.setup_ui()
    
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.window, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 日志文件模式设置
        pattern_frame = ttk.Frame(main_frame)
        pattern_frame.pack(fill=tk.X, pady=5)
        ttk.Label(pattern_frame, text="日志文件模式:").pack(side=tk.LEFT)
        self.pattern_entry = ttk.Entry(pattern_frame)
        self.pattern_entry.pack(side=tk.RIGHT, fill=tk.X, expand=True, padx=(10, 0))
        self.pattern_entry.insert(0, self.pattern_var.get())
        
        # 输出目录设置
        output_frame = ttk.Frame(main_frame)
        output_frame.pack(fill=tk.X, pady=5)
        ttk.Label(output_frame, text="输出目录:").pack(side=tk.LEFT)
        self.output_entry = ttk.Entry(output_frame)
        self.output_entry.pack(side=tk.RIGHT, fill=tk.X, expand=True, padx=(10, 0))
        self.output_entry.insert(0, self.output_dir_var.get())
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(20, 0))
        
        save_btn = ttk.Button(button_frame, text="保存", command=self.save_settings)
        save_btn.pack(side=tk.RIGHT, padx=(5, 0))
        
        cancel_btn = ttk.Button(button_frame, text="取消", command=self.window.destroy)
        cancel_btn.pack(side=tk.RIGHT)
    
    def save_settings(self):
        self.pattern_var.set(self.pattern_entry.get())
        self.output_dir_var.set(self.output_entry.get())
        self.window.destroy()


class RuleManagerWindow:
    """规则管理窗口"""
    def __init__(self, parent, analyzer, refresh_callback):
        self.parent = parent
        self.analyzer = analyzer
        self.refresh_callback = refresh_callback  # 回调函数，用于刷新主界面
        self.window = tk.Toplevel(parent)
        self.window.title("规则管理")
        self.window.geometry("500x400")
        self.window.transient(parent)
        self.window.grab_set()
        
        self.setup_ui()
        self.refresh_rules()
    
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.window, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(0, 10))
        
        add_btn = ttk.Button(button_frame, text="添加规则", command=self.add_rule)
        add_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        edit_btn = ttk.Button(button_frame, text="编辑规则", command=self.edit_rule)
        edit_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        del_btn = ttk.Button(button_frame, text="删除规则", command=self.delete_rule)
        del_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        # 规则列表
        list_frame = ttk.Frame(main_frame)
        list_frame.pack(fill=tk.BOTH, expand=True)
        
        self.rules_listbox = tk.Listbox(list_frame)
        self.rules_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.rules_listbox.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.rules_listbox.configure(yscrollcommand=scrollbar.set)
        
        # 关闭按钮
        close_btn = ttk.Button(main_frame, text="关闭", command=self.window.destroy)
        close_btn.pack(pady=(10, 0))
    
    def refresh_rules(self):
        self.rules_listbox.delete(0, tk.END)
        rules = self.analyzer.list_rules()
        for rule in rules:
            self.rules_listbox.insert(tk.END, f"{rule['name']}: {rule['pattern']}")
    
    def add_rule(self):
        name = simpledialog.askstring("添加规则", "规则名称:")
        if not name:
            return
        
        pattern = simpledialog.askstring("添加规则", "正则表达式模式:")
        if pattern is not None:
            self.analyzer.add_rule(name, pattern)
            self.refresh_rules()
            # 自动刷新主界面
            if self.refresh_callback:
                self.refresh_callback()
    
    def edit_rule(self):
        selection = self.rules_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个规则")
            return
        
        index = selection[0]
        rules = self.analyzer.list_rules()
        if index >= len(rules):
            return
        
        rule = rules[index]
        name = simpledialog.askstring("编辑规则", "规则名称:", initialvalue=rule['name'])
        if name is None:
            return
        
        pattern = simpledialog.askstring("编辑规则", "正则表达式模式:", initialvalue=rule['pattern'])
        if pattern is not None:
            self.analyzer.update_rule(index, name, pattern)
            self.refresh_rules()
            # 自动刷新主界面
            if self.refresh_callback:
                self.refresh_callback()
    
    def delete_rule(self):
        selection = self.rules_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个规则")
            return
        
        index = selection[0]
        rules = self.analyzer.list_rules()
        if index >= len(rules):
            return
        
        rule = rules[index]
        if messagebox.askyesno("确认删除", f"确定要删除规则 '{rule['name']}' 吗?"):
            self.analyzer.delete_rule(index)
            self.refresh_rules()
            # 自动刷新主界面
            if self.refresh_callback:
                self.refresh_callback()


class LogAnalyzerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("日志分析工具")
        self.root.geometry("900x700")
        
        self.analyzer = LogAnalyzer()
        self.selected_file = None
        self.extracted_files = []
        self.log_files = []
        self.current_filtered_result = None  # 保存当前过滤结果
        
        # 设置变量
        self.pattern_var = tk.StringVar(value="*.log")
        self.output_dir_var = tk.StringVar(value="./extracted_logs")
        
        self.setup_ui()
        self.refresh_filter_buttons()
    
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(2, weight=1)
        
        # 菜单栏
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        # 设置菜单
        settings_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="设置", menu=settings_menu)
        settings_menu.add_command(label="常规设置", command=self.open_settings)
        settings_menu.add_command(label="规则管理", command=self.open_rule_manager)
        
        # 选择文件区域
        ttk.Label(main_frame, text="选择压缩文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.file_path_var = tk.StringVar()
        file_entry = ttk.Entry(main_frame, textvariable=self.file_path_var, width=50, state="readonly")
        file_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=(10, 10), pady=5)
        
        browse_button = ttk.Button(main_frame, text="浏览...", command=self.browse_file)
        browse_button.grid(row=0, column=2, pady=5, sticky=tk.N)
        
        # 过滤按钮区域（直接作用于原始文件）
        ttk.Label(main_frame, text="基于原始文件过滤:").grid(row=1, column=0, columnspan=3, sticky=tk.W)
        self.filter_buttons_frame = ttk.Frame(main_frame)
        self.filter_buttons_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(2, 5))  # 减小上下间距
        
        # 日志显示区域
        log_frame = ttk.LabelFrame(main_frame, text="日志内容（右键可基于当前结果继续过滤）", padding="10")
        log_frame.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
        log_frame.columnconfigure(0, weight=1)
        log_frame.rowconfigure(0, weight=1)
        main_frame.rowconfigure(3, weight=1)
        main_frame.rowconfigure(2, weight=0)  # 确保按钮区域不会被拉伸
        self.log_text = tk.Text(log_frame, wrap=tk.WORD)
        self.log_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        log_frame.rowconfigure(0, weight=1)
        log_frame.columnconfigure(0, weight=1)
        
        log_scrollbar = ttk.Scrollbar(log_frame, orient="vertical", command=self.log_text.yview)
        log_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
        self.log_text.configure(yscrollcommand=log_scrollbar.set)
        
        # 绑定右键菜单事件
        self.log_text.bind("<Button-3>", self.show_context_menu)
        self.context_menu = tk.Menu(self.log_text, tearoff=0)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(10, 0))
    
    def open_settings(self):
        """打开设置窗口"""
        SettingsWindow(self.root, self.pattern_var, self.output_dir_var)
    
    def show_context_menu(self, event):
        """显示右键菜单"""
        # 先清空现有菜单项
        self.context_menu.delete(0, tk.END)
        
        # 添加基于当前结果过滤的菜单项
        rules = self.analyzer.list_rules()
        if rules:
            self.context_menu.add_command(label="基于当前结果过滤:", state="disabled")
            for i, rule in enumerate(rules):
                self.context_menu.add_command(
                    label=rule['name'], 
                    command=lambda idx=i: self.filter_on_current_result(idx)
                )
            self.context_menu.add_separator()
        
        self.context_menu.add_command(label="清空结果", command=self.clear_results)
        self.context_menu.add_command(label="复制选中内容", command=self.copy_selection)
        
        # 显示菜单
        self.context_menu.post(event.x_root, event.y_root)
    
    def clear_results(self):
        """清空结果显示"""
        self.log_text.delete(1.0, tk.END)
        self.current_filtered_result = None
    
    def copy_selection(self):
        """复制选中内容"""
        try:
            selected_text = self.log_text.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.root.clipboard_clear()
            self.root.clipboard_append(selected_text)
        except tk.TclError:
            # 没有选中内容
            pass
    
    def open_rule_manager(self):
        """打开规则管理窗口"""
        RuleManagerWindow(self.root, self.analyzer, self.refresh_filter_buttons)
    
    def refresh_filter_buttons(self):
        """刷新过滤按钮"""
        for widget in self.filter_buttons_frame.winfo_children():
            widget.destroy()
        
        rules = self.analyzer.list_rules()
        for i, rule in enumerate(rules):
            btn = ttk.Button(
                self.filter_buttons_frame, 
                text=rule['name'], 
                command=lambda idx=i: self.filter_logs(idx)  # 直接作用于原始文件
            )
            btn.pack(side=tk.LEFT, padx=(0, 5))
    
    def browse_file(self):
        file_path = filedialog.askopenfilename(
            title="选择压缩文件",
            filetypes=[
                ("压缩文件", "*.zip *.tar.gz *.tgz *.tar.bz2 *.tbz2 *.7z"),
                ("所有文件", "*.*")
            ]
        )
        
        if file_path:
            self.file_path_var.set(file_path)
            self.selected_file = file_path
            self.status_var.set(f"已选择文件: {os.path.basename(file_path)}")
            # 自动处理文件
            self.process_files()
    
    def process_files(self):
        if not self.selected_file:
            messagebox.showwarning("警告", "请先选择一个压缩文件")
            return
        
        # 在后台线程中处理文件
        threading.Thread(target=self._process_files_thread, daemon=True).start()
    
    def _process_files_thread(self):
        self.root.after(0, lambda: self.status_var.set("正在解压文件..."))
        
        try:
            # 创建临时解压目录
            temp_extract_dir = "./temp_extracted"
            os.makedirs(temp_extract_dir, exist_ok=True)
            
            # 解压文件
            self.extracted_files = self.analyzer.extract_archive(
                self.selected_file, temp_extract_dir)
            
            self.root.after(0, lambda: self.status_var.set("正在筛选日志文件..."))
            
            # 筛选日志文件
            pattern = self.pattern_var.get() or "*.log"
            self.log_files = self.analyzer.filter_log_files(temp_extract_dir, pattern)
            
            # 复制到输出目录
            output_dir = self.output_dir_var.get() or "./extracted_logs"
            self.analyzer.copy_files_to_directory(self.log_files, output_dir)
            
            self.root.after(0, lambda: self.status_var.set(f"处理完成，找到 {len(self.log_files)} 个日志文件"))
            self.root.after(0, lambda: messagebox.showinfo("完成", f"处理完成，找到 {len(self.log_files)} 个日志文件"))
            
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", f"处理文件时出错: {str(e)}"))
            self.root.after(0, lambda: self.status_var.set("处理失败"))
    
    def filter_logs(self, rule_index):
        """基于原始日志文件进行过滤"""
        if not self.log_files:
            messagebox.showwarning("警告", "请先解压并筛选日志文件")
            return
        
        # 在后台线程中过滤日志
        threading.Thread(target=self._filter_logs_thread, args=(rule_index, True), daemon=True).start()
    
    def filter_on_current_result(self, rule_index):
        """基于当前结果进行过滤"""
        if not self.log_files:
            messagebox.showwarning("警告", "请先解压并筛选日志文件")
            return
        
        if not self.current_filtered_result:
            messagebox.showwarning("警告", "当前没有过滤结果可供进一步过滤")
            return
        
        # 在后台线程中过滤日志
        threading.Thread(target=self._filter_logs_thread, args=(rule_index, False), daemon=True).start()
    
    def _filter_logs_thread(self, rule_index, use_original_files):
        self.root.after(0, lambda: self.status_var.set("正在过滤日志..."))
        
        try:
            if use_original_files:
                # 基于原始文件进行过滤
                result = self.analyzer.filter_logs_by_rule(self.log_files, rule_index)
                # 保存结果供后续使用
                self.current_filtered_result = result
            else:
                # 基于当前结果进行过滤
                result = self.analyzer.filter_logs_by_rule(self.log_files, rule_index)
                # 只保留在当前结果中也存在的条目
                filtered_result = {}
                for file_path, lines in result.items():
                    if file_path in self.current_filtered_result:
                        # 获取两个结果的交集
                        current_lines = set(self.current_filtered_result[file_path])
                        new_lines = []
                        for line in lines:
                            # 检查行是否在当前结果中存在
                            for current_line in current_lines:
                                if line == current_line:
                                    new_lines.append(line)
                                    break
                        
                        if new_lines:
                            filtered_result[file_path] = new_lines
                
                # 更新当前结果
                self.current_filtered_result = filtered_result if filtered_result else result
            
            # 在文本区域显示结果
            self.root.after(0, self.log_text.delete, 1.0, tk.END)
            
            if not self.current_filtered_result:
                self.root.after(0, self.log_text.insert, tk.END, "未找到匹配的日志条目\n")
            else:
                for file_path, lines in self.current_filtered_result.items():
                    self.root.after(0, self.log_text.insert, tk.END, f"\n=== {file_path} ===\n")
                    for line in lines:
                        self.root.after(0, self.log_text.insert, tk.END, line + "\n")
            
            self.root.after(0, lambda: self.status_var.set("过滤完成"))
            
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", f"过滤日志时出错: {str(e)}"))
            self.root.after(0, lambda: self.status_var.set("过滤失败"))


def main():
    root = tk.Tk()
    app = LogAnalyzerGUI(root)
    root.mainloop()


if __name__ == "__main__":
    main()